/**
 * 作者:hanbo
 * 日期:2018/11/1915:40
 * 描述:
 */
import 'jquery';
import {WebGL} from "../webgl/WebGL";
import {ImageBrush} from "../brush/ImageBrush";
import {EXTENDS_3857} from "./Constant";
import {PointsBrush} from "../brush/PointsBrush";
import {LinesBrush} from "../brush/LinesBrush";
import {PointStyle} from "../geometry/style/PointStyle";
import {Polygon} from "../geometry/Polygon";
import {PolygonsBrush} from "../brush/PolygonsBrush";
import {WideLinesBrush} from "../brush/WideLinesBrush";
import {PolylinesBrush} from "../brush/PolylinesBrush";
import {WidePolyLinesBrush} from "../brush/WidePolyLinesBrush";


export class MapRender {
    constructor(mapView, id) {
        this._mapView = mapView;
        let container = $("#" + id);
        let width = container.width();
        let height = container.height();
        //初始化正交矩阵
        this._mapView.gLStateCenter.setOProjection(width, height);
        //在div内添加canvas
        let className = 'h_map';
        let canvas = $(`<canvas class=${className} width=${width} height=${height}></canvas>`);
        container.append(canvas);

        this._canvas = canvas.get(0);
        this._webGL = WebGL.getWebGLContext(this._canvas);
        this._webGL.viewport(0, 0, width, height);
        //console.log(this._webGL.getParameter(this._webGL.MAX_COMBINED_TEXTURE_IMAGE_UNITS));//获取GPU最大纹理单元
        this._mapView._interactiveEvent.init(id);
        this._init();
    }

    /**
     * 初始化设置
     */
    _init() {
        //设置背景色
        this._webGL.clearColor(0, 0, 0, 0);
        //隐藏面剔除技术
        this._webGL.enable(this._webGL.DEPTH_TEST);
        this._webGL.depthFunc(this._webGL.LEQUAL);
        this._webGL.clearDepth(1.0);
        //遮挡剔除
        // this._webGL.enable(this._webGL.CULL_FACE);
        //色彩混合

        this._webGL.pixelStorei(this._webGL.UNPACK_FLIP_Y_WEBGL, 1); // 翻转图像Y轴
        //指定颜色混合函数
        this._webGL.enable(this._webGL.BLEND);
        this._webGL.blendFunc(this._webGL.ONE, this._webGL.ONE_MINUS_SRC_ALPHA);
        this._brushs = [];
        this._clear();

        this._canvas.addEventListener('webglcontextlost', MapRender.contextLost, false);
        this._canvas.addEventListener('webglcontextrestored', this.contextRestored, false);

        window.that = this;
        requestAnimationFrame(this._render);
    }

    /**
     * 清空画布
     */
    _clear() {
        this._webGL.clear(this._webGL.COLOR_BUFFER_BIT);
        this._webGL.clear(this._webGL.DEPTH_BUFFER_BIT);
        //清除
        this._brushs.forEach(function (brush) {
            brush.clear();
        });
    }

    /**
     * webGL上下文丢失事件
     * @param ev
     */
    contextLost(ev) {
        // this._webGL = WebGL.getWebGLContext(this._canvas);
        ev.preventDefault();
    }

    /**
     * webGL上下文恢复响应事件
     * @param ev
     */
    contextRestored(ev) {
        this._webGL = WebGL.getWebGLContext(this._canvas);
    }

    /**
     * 批量绘制同颜色点
     * @param points {Array} 点数组
     * @param uuid {String} 所属图层id
     * @param style {PointStyle} 点大小
     * @param layerAmount {number} 图层数量
     * @param layerIndex {number} 图层索引
     */
    drawPoints(points, uuid, layerAmount, layerIndex, style) {
        let brush = new PointsBrush(this._webGL);
        let n = points.length;
        let float32Array;
        const baseIndex = layerIndex / layerAmount;
        float32Array = new Float32Array(n * 7);
        let point;
        if (style) {
            for (let i = 0; i < n; i++) {
                point = points[i];
                float32Array[i * 7] = point.x / EXTENDS_3857;
                float32Array[i * 7 + 1] = point.y / EXTENDS_3857;
                float32Array[i * 7 + 2] = baseIndex;
                float32Array[i * 7 + 3] = style.pointSize;
                float32Array[i * 7 + 4] = style.color.r;
                float32Array[i * 7 + 5] = style.color.g;
                float32Array[i * 7 + 6] = style.color.b;
            }

        } else {
            for (let i = 0; i < n; i++) {
                point = points[i];
                float32Array[i * 7] = point.x / EXTENDS_3857;
                float32Array[i * 7 + 1] = point.y / EXTENDS_3857;
                float32Array[i * 7 + 2] = baseIndex;
                //如果点无样式，默认添加点样式
                let pointStyle = point.getStyle();
                float32Array[i * 7 + 3] = pointStyle.pointSize;
                float32Array[i * 7 + 4] = pointStyle.color.r;
                float32Array[i * 7 + 5] = pointStyle.color.g;
                float32Array[i * 7 + 6] = pointStyle.color.b;
            }
        }
        brush.drawPoints(float32Array, n);
        brush.setLayer(uuid);
        this._brushs.push(brush);
    }

    /**
     * 批量绘制同颜色线
     * @param lines {Array} 线图层数组
     * @param uuid {String} 所属图层id
     * @param style {LineStyle} 线样式
     * @param layerAmount {number} 图层数量
     * @param layerIndex {number} 图层索引
     */
    drawLines(lines, uuid, layerAmount, layerIndex, style) {
        let brush = new LinesBrush(this._webGL);
        let n = lines.length;
        const baseIndex = layerIndex / layerAmount;
        let float32Array;
        let line;
        if (style) {
            if (style.width !== 1) {//线宽不为1转画宽度线
                this.drawWideLines(lines, uuid, baseIndex, style);
                return
            }
            float32Array = new Float32Array(n * 14);
            for (let i = 0; i < n; i++) {
                line = lines[i];
                float32Array[i * 14] = line.point1.x / EXTENDS_3857;
                float32Array[i * 14 + 1] = line.point1.y / EXTENDS_3857;
                float32Array[i * 14 + 2] = baseIndex;
                float32Array[i * 14 + 3] = style.color.r;
                float32Array[i * 14 + 4] = style.color.g;
                float32Array[i * 14 + 5] = style.color.b;
                float32Array[i * 14 + 6] = style.opacity;
                float32Array[i * 14 + 7] = line.point2.x / EXTENDS_3857;
                float32Array[i * 14 + 8] = line.point2.y / EXTENDS_3857;
                float32Array[i * 14 + 9] = float32Array[i * 14 + 2];
                float32Array[i * 14 + 10] = style.color.r;
                float32Array[i * 14 + 11] = style.color.g;
                float32Array[i * 14 + 12] = style.color.b;
                float32Array[i * 14 + 13] = style.opacity;
            }
        } else {
            let lineWithWidth = [];
            let lineNoWidth = [];
            //筛选有无宽度线
            for (let i = 0; i < lines.length; i++) {
                if (lines[i].getStyle().width === 1) {
                    lineNoWidth.push(lines[i])
                } else {
                    lineWithWidth.push(lines[i])
                }
            }
            if (lineWithWidth.length) {
                this.drawWideLines(lineWithWidth, uuid, baseIndex);
            }
            if (!lineNoWidth.length) {
                return
            }
            float32Array = new Float32Array(lineNoWidth.length * 14);
            let lineStyle;
            for (let i = 0; i < lineNoWidth.length; i++) {
                line = lineNoWidth[i];
                lineStyle = line.getStyle();
                float32Array[i * 14] = line.point1.x / EXTENDS_3857;
                float32Array[i * 14 + 1] = line.point1.y / EXTENDS_3857;
                float32Array[i * 14 + 2] = baseIndex;
                float32Array[i * 14 + 3] = lineStyle.color.r;
                float32Array[i * 14 + 4] = lineStyle.color.g;
                float32Array[i * 14 + 5] = lineStyle.color.b;
                float32Array[i * 14 + 6] = lineStyle.opacity;
                float32Array[i * 14 + 7] = line.point2.x / EXTENDS_3857;
                float32Array[i * 14 + 8] = line.point2.y / EXTENDS_3857;
                float32Array[i * 14 + 9] = float32Array[i * 14 + 2];
                float32Array[i * 14 + 10] = lineStyle.color.r;
                float32Array[i * 14 + 11] = lineStyle.color.g;
                float32Array[i * 14 + 12] = lineStyle.color.b;
                float32Array[i * 14 + 13] = lineStyle.opacity;
            }
        }
        brush.drawLines(float32Array, 2 * n);//点数等于线数乘以2
        brush.setLayer(uuid);
        this._brushs.push(brush);
    }

    /**
     *
     * @param lines {Array} 线图层数组
     * @param uuid {String} 所属图层id
     * @param index {number} 深度信息
     * @param style {LineStyle} 线样式
     */
    drawWideLines(lines, uuid, index, style) {
        let brush = new WideLinesBrush(this._webGL, this);
        //转换到GL绘图坐标系
        lines.forEach(function (line) {
            line.toGLCoordinate()
        });
        brush.drawLines(lines, index, style);
        brush.setLayer(uuid);
        this._brushs.push(brush);
    }

    /**
     * 绘制地图切片
     * @param img {Image} 已加载完成image对象
     * @param rectangle {Rectangle} 坐标范围
     * @param uuid {String} 所属图层id
     * @param z {Number} 深度值
     */
    drawImageLoad(img, rectangle, uuid, z) {
        let imageBrush = new ImageBrush(this._webGL, this._textureIndex);
        imageBrush.setLayer(uuid);
        this._textureIndex++;
        imageBrush.drawImageLoad(img, rectangle.xMin / EXTENDS_3857, rectangle.yMin / EXTENDS_3857, rectangle.xMax / EXTENDS_3857, rectangle.yMax / EXTENDS_3857, z);
        this._brushs.push(imageBrush);
    }

    /**
     * 绘制矩形
     * @param rectangles {Rectangle[]} 矩形
     * @param uuid {String} 图层id
     * @param style {PointStyle} 图层样式
     * @param layerAmount {number} 图层数量
     * @param layerIndex {number} 图层索引
     */
    drawRectangles(rectangles, uuid, layerAmount, layerIndex, style) {

    }

    /**
     * 绘制矩形
     * @param polygons {Polygon[]} 矩形
     * @param uuid {String} 图层id
     * @param style {PointStyle} 图层样式
     * @param layerAmount {number} 图层数量
     * @param layerIndex {number} 图层索引
     */
    drawPolygons(polygons, uuid, layerAmount, layerIndex, style) {
        let brush = new PolygonsBrush(this._webGL);
        const amount = Polygon.getPointAmount(polygons);//所有多边形点数
        let n = polygons.length;
        let currentIndex = 0;//Float32Array中存储索引
        let pointAmount = [];//每个多边形点数
        let float32Array;
        let polygon;
        if (style) {
            float32Array = new Float32Array(amount * 3);
            for (let i = 0; i < n; i++) {
                polygon = polygons[i];
                pointAmount.push(polygon.array.length);
                for (let j = 0; j < polygon.array.length; j++) {
                    float32Array[currentIndex] = polygon.array[j][0] / EXTENDS_3857;
                    currentIndex++;
                    float32Array[currentIndex] = polygon.array[j][1] / EXTENDS_3857;
                    currentIndex++;
                    float32Array[currentIndex] = i / n;
                    currentIndex++
                }
            }
        }
        else {
            float32Array = new Float32Array(amount * 5);
            let polygonStyle;
            for (let i = 0; i < n; i++) {
                polygon = polygons[i];
                polygonStyle = polygon.getStyle();
                pointAmount.push(polygon.array.length);
                for (let j = 0; j < polygon.array.length; j++) {
                    float32Array[currentIndex] = polygon.array[j][0] / EXTENDS_3857;
                    currentIndex++;
                    float32Array[currentIndex] = polygon.array[j][1] / EXTENDS_3857;
                    currentIndex++;
                    float32Array[currentIndex] = polygon.array[j][1] / EXTENDS_3857;
                    currentIndex++;
                    float32Array[currentIndex] = polygon.array[j][1] / EXTENDS_3857;
                    currentIndex++;
                    float32Array[currentIndex] = polygon.array[j][1] / EXTENDS_3857;
                    currentIndex++;
                }
            }
        }
        brush.drawPolygons(float32Array, pointAmount, style);
        brush.setLayer(uuid);
        this._brushs.push(brush);
    }

    /**
     * 批量绘制多段线
     * @param polyLines {Polyline[]} 矩形
     * @param uuid {String} 图层id
     * @param style {LineStyle} 图层样式
     * @param layerAmount {number} 图层数量
     * @param layerIndex {number} 图层索引
     */
    drawPolyLines(polyLines, uuid, layerAmount, layerIndex, style) {
        let brush;
        const baseIndex = layerIndex / layerAmount;
        let pointMount = 0;//总点数
        let edgePointMount = [];//每个多段线的点数
        let floatArray;
        let currentIndex = 0;
        let polyline;
        if (style) {
            if (style.width !== 1) {
                this.drawWidePolyLines(polyLines, uuid, baseIndex, style);
                return
            }
            brush = new PolylinesBrush(this._webGL);
            for (let i = 0; i < polyLines.length; i++) {
                edgePointMount[i] = polyLines[i].path.length;
                pointMount = pointMount + edgePointMount[i];
            }
            floatArray = new Float32Array(pointMount * 7);
            for (let i = 0; i < polyLines.length; i++) {
                polyline = polyLines[i];
                for (let j = 0; j < polyline.path.length; j++) {
                    floatArray[currentIndex] = polyline.path[j][0] / EXTENDS_3857;
                    currentIndex++;
                    floatArray[currentIndex] = polyline.path[j][1] / EXTENDS_3857;
                    currentIndex++;
                    floatArray[currentIndex] = baseIndex;
                    currentIndex++;
                    floatArray[currentIndex] = style.color.r;
                    currentIndex++;
                    floatArray[currentIndex] = style.color.g;
                    currentIndex++;
                    floatArray[currentIndex] = style.color.b;
                    currentIndex++;
                    floatArray[currentIndex] = style.opacity;
                    currentIndex++;
                }
            }
        } else {
            let lineWithWidth = [];
            let lineNoWidth = [];
            //筛选有无宽度线
            for (let i = 0; i < polyLines.length; i++) {
                if (polyLines[i].getStyle().width === 1) {
                    lineNoWidth.push(polyLines[i])
                } else {
                    lineWithWidth.push(polyLines[i])
                }
            }
            if (lineWithWidth.length) {
                this.drawWidePolyLines(lineWithWidth, uuid, baseIndex,style);
            }
            if (!lineNoWidth.length) {
                return
            }
            brush = new PolylinesBrush(this._webGL);
            for (let i = 0; i < lineNoWidth.length; i++) {
                edgePointMount[i] = lineNoWidth[i].path.length;
                pointMount = pointMount + edgePointMount[i];
            }
            floatArray = new Float32Array(pointMount * 7);
            for (let i = 0; i < lineNoWidth.length; i++) {
                polyline = lineNoWidth[i];
                let lineStyle = polyline.getStyle();
                for (let j = 0; j < polyline.path.length; j++) {
                    floatArray[currentIndex] = polyline.path[j][0] / EXTENDS_3857;
                    currentIndex++;
                    floatArray[currentIndex] = polyline.path[j][1] / EXTENDS_3857;
                    currentIndex++;
                    floatArray[currentIndex] = baseIndex;
                    currentIndex++;
                    floatArray[currentIndex] = lineStyle.color.r;
                    currentIndex++;
                    floatArray[currentIndex] = lineStyle.color.g;
                    currentIndex++;
                    floatArray[currentIndex] = lineStyle.color.b;
                    currentIndex++;
                    floatArray[currentIndex] = lineStyle.opacity;
                    currentIndex++;
                }
            }
        }
        brush.drawLines(floatArray, edgePointMount);
        brush.setLayer(uuid);
        this._brushs.push(brush);
    }

    /**
     * 绘制带宽度多段线
     * @param polyLines {Polyline[]}
     * @param uuid {String} 图层id
     * @param style {LineStyle} 图层样式
     * @param z {Number} 深度值
     */
    drawWidePolyLines(polyLines, uuid, z, style) {
        let brush = new WidePolyLinesBrush(this._webGL,this);
        polyLines.forEach(function (polyline) {
            polyline.toGLCoordinate();
        });
        brush.drawLines(polyLines,z,style);
        brush.setLayer(uuid);
        this._brushs.push(brush);
    }

    /**
     * 通过所属图层的id移除画笔
     * @param uuid {String} 图层id
     */
    removeBrushByLayer(uuid) {
        let targets = [];
        for (let i = 0; i < this._brushs.length; i++) {
            let brush = this._brushs[i];
            if (brush.layer && brush.layer == uuid) {
                targets.push(i);
            }
        }
        //从后向前删除
        for (let i = targets.length; i > 0; i++) {
            this._brushs.splice(i - 1, 1)
        }
    }

    /**
     * 实时渲染
     * @private
     */
    _render() {
        //注意此仇全部使用that
        that._clear();
        let projection = that._mapView.gLStateCenter.getProjection();
        that._brushs.forEach(function (brush) {
            brush.draw(projection);
        });
        requestAnimationFrame(that._render);
    }

    /**
     * 移除绘制任务
     * @param brush [BaseBrush] 画笔
     */
    removeBrush(brush) {
        for (let i = this._brushs.length - 1; i >= 0; i++) {
            if (this._brushs[i].uuid == brush.uuid) {
                this._brushs.splice(i, 1);
                break;
            }
        }
    }

    clear() {
        this._brushs = [];
        this._textureIndex = 0;//纹理索引
    }

    /**
     * 获取坐标1米对应的像素值
     */
    getPixel_per_Meter() {
        return this._mapView.gLStateCenter.getPixel_per_Meter();
    }

    /**
     * 获取每像素对应的GL单位
     * @return {Number}
     */
    getUnitPerPixel() {
        return this._mapView.gLStateCenter.getUnit_per_Pixel();
    }

    /**
     * 通过像素宽度将线转化为面
     * @param line
     * @param pixel
     */
    lineToRectangle(line, pixel) {

    }
}